﻿//----------------------------------------------------------------
// Desc: 对象仓库
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2012-11-22
//
// Update Date :
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


#include <typeinfo>


//----------------------------------------------------------------
// FNewObject 函数的不定参数，及不定参数数量定义
//----------------------------------------------------------------
#define FNEW_TYPEN(N)    class _TY##N
#define FNEW_PARAM(N)    _TY##N pv##N
#define FNEW_VALUE(N)    pv##N

#define FNEW_TYPEN0
#define FNEW_TYPEN1      FNEW_TYPEN0,     FNEW_TYPEN(1)
#define FNEW_TYPEN2      FNEW_TYPEN1,     FNEW_TYPEN(2)
#define FNEW_TYPEN3      FNEW_TYPEN2,     FNEW_TYPEN(3)
#define FNEW_TYPEN4      FNEW_TYPEN3,     FNEW_TYPEN(4)
#define FNEW_TYPEN5      FNEW_TYPEN4,     FNEW_TYPEN(5)
#define FNEW_TYPEN6      FNEW_TYPEN5,     FNEW_TYPEN(6)
#define FNEW_TYPEN7      FNEW_TYPEN6,     FNEW_TYPEN(7)
#define FNEW_TYPEN8      FNEW_TYPEN7,     FNEW_TYPEN(8)
#define FNEW_TYPEN9      FNEW_TYPEN8,     FNEW_TYPEN(9)
#define FNEW_TYPEN10     FNEW_TYPEN9,     FNEW_TYPEN(10)

#define FNEW_PARAM0      FNEW_FUNC_API
#define FNEW_PARAM1      FNEW_PARAM0,     FNEW_PARAM(1)
#define FNEW_PARAM2      FNEW_PARAM1,     FNEW_PARAM(2)
#define FNEW_PARAM3      FNEW_PARAM2,     FNEW_PARAM(3)
#define FNEW_PARAM4      FNEW_PARAM3,     FNEW_PARAM(4)
#define FNEW_PARAM5      FNEW_PARAM4,     FNEW_PARAM(5)
#define FNEW_PARAM6      FNEW_PARAM5,     FNEW_PARAM(6)
#define FNEW_PARAM7      FNEW_PARAM6,     FNEW_PARAM(7)
#define FNEW_PARAM8      FNEW_PARAM7,     FNEW_PARAM(8)
#define FNEW_PARAM9      FNEW_PARAM8,     FNEW_PARAM(9)
#define FNEW_PARAM10     FNEW_PARAM9,     FNEW_PARAM(10)

#define FNEW_VALUE0
#define FNEW_VALUE1      FNEW_VALUE0      FNEW_VALUE(1)
#define FNEW_VALUE2      FNEW_VALUE1,     FNEW_VALUE(2)
#define FNEW_VALUE3      FNEW_VALUE2,     FNEW_VALUE(3)
#define FNEW_VALUE4      FNEW_VALUE3,     FNEW_VALUE(4)
#define FNEW_VALUE5      FNEW_VALUE4,     FNEW_VALUE(5)
#define FNEW_VALUE6      FNEW_VALUE5,     FNEW_VALUE(6)
#define FNEW_VALUE7      FNEW_VALUE6,     FNEW_VALUE(7)
#define FNEW_VALUE8      FNEW_VALUE7,     FNEW_VALUE(8)
#define FNEW_VALUE9      FNEW_VALUE8,     FNEW_VALUE(9)
#define FNEW_VALUE10     FNEW_VALUE9,     FNEW_VALUE(10)


//----------------------------------------------------------------
// 从 Fuel4D 的对象内存池中分配特定对象，该对象须从IFMemObject继承或者填写有FDECLARE_STRUCT宏。
//----------------------------------------------------------------
// 获取对象仓库管理器地址
class IFObjectFactory;
extern FAPI IFObjectFactory* FGetObjFactory();


//----------------------------------------------------------------
// 最大支持10个构造参数的对象池分配
//----------------------------------------------------------------
#define FNEW_OBJECT(N)\
template < typename _Ty FNEW_TYPEN##N >\
FINLINE _Ty* FNewObject(FNEW_PARAM##N)\
{\
    _Ty* p = FGetObjFactory()->allocate< _Ty >(file, line, func, _Ty::_StaticClassName());\
    if (!p)\
        return 0;\
    return (_Ty*)FNewPP(p) _Ty(FNEW_VALUE##N);\
}


//----------------------------------------------------------------
// 释放一个由对象池分析的对象
//----------------------------------------------------------------
template < typename _Ty >
FINLINE bool FDelObject(_Ty*& p);


//----------------------------------------------------------------
//
//----------------------------------------------------------------
class IFObjectFactory : public IFMemObject
{
protected:
    explicit IFObjectFactory()
    {}
    virtual~IFObjectFactory()
    {}

public:
    struct mem_info
    {
        size_t count;           // 对象在内存中的使用数量
        size_t capacity;        // 对象在内存中的总计缓存数量
        size_t obj_size;        // 单个对象占用内存大小

        mem_info()
            :count(0)
            ,capacity(0)
            ,obj_size(0)
        {}
    };

    struct pool_interface : public IFMemObject
    {
        ACHAR obj_name[80];
        pool_interface(){}
        virtual~pool_interface(){}
        virtual void* allocate(FNEW_FUNC) = 0;
        virtual bool deallocate(void* p, bool _call_del) = 0;
        virtual void tidy() = 0;
        virtual void get_info(mem_info& out) = 0;
    };

    template < typename _Ty >
    _Ty* allocate(FNEW_FUNC)
    {
        FLock_Auto __lk(cs);
        FIDHASH id = FGetHashA(typeid(_Ty).name());
        pool_interface* po = find(id);
        if (!po)
            po = registration< _Ty >();
        if (!po)
            return 0;
        return (_Ty*)po->allocate(FNEW_PASS);
    }
    template < typename _Ty >
    bool deallocate(_Ty* p, bool _call_del = true)
    {
        FLock_Auto __lk(cs);
        FIDHASH id = FGetHashA(typeid(*p).name());
        pool_interface* po = find(id);
        if (po)
            return po->deallocate(p, _call_del);
        return false;
    }

    template < typename _Ty, const WORD size = 64>
    class memory_pool : public pool_interface
    {
        FDECLARE_CLASS(IFObjectFactory::memory_pool)

    public:
        virtual void* allocate(FNEW_FUNC)
        {
            return (void*)vData.allocate(FNEW_PASS_API);
        }
        virtual bool deallocate(void* p, bool _call_del)
        {
            return vData.deallocate((_Ty*&)p, _call_del);
        }
        virtual void tidy()
        {
            vData.tidy();
        }
        virtual void get_info(mem_info& out)
        {
            out.count = vData.size();
            out.capacity = vData.capacity();
            out.obj_size = vData.obj_size();
        }

        FMemoryPool< _Ty, size, FLock_Nil > vData;
    };
    template < typename _Ty >
    pool_interface* registration(WORD size = 64)
    {
        FIDHASH id = FGetHashA(typeid(_Ty).name());
        pool_interface* po = find(id);
        if (po)
            return po;
        typedef memory_pool< _Ty,    1 > _pool_type____1;
        typedef memory_pool< _Ty,    2 > _pool_type____2;
        typedef memory_pool< _Ty,    4 > _pool_type____4;
        typedef memory_pool< _Ty,    8 > _pool_type____8;
        typedef memory_pool< _Ty,   16 > _pool_type___16;
        typedef memory_pool< _Ty,   32 > _pool_type___32;
        typedef memory_pool< _Ty,   64 > _pool_type___64;
        typedef memory_pool< _Ty,  128 > _pool_type__128;
        typedef memory_pool< _Ty,  256 > _pool_type__256;
        typedef memory_pool< _Ty,  512 > _pool_type__512;
        typedef memory_pool< _Ty, 1024 > _pool_type_1024;
        typedef memory_pool< _Ty, 2048 > _pool_type_2048;
        typedef memory_pool< _Ty, 4096 > _pool_type_4096;
        typedef memory_pool< _Ty, 8192 > _pool_type_8192;
        switch (size)
        {
        case    1: po = FNew(_pool_type____1); break;
        case    2: po = FNew(_pool_type____2); break;
        case    4: po = FNew(_pool_type____4); break;
        case    8: po = FNew(_pool_type____8); break;
        case   16: po = FNew(_pool_type___16); break;
        case   32: po = FNew(_pool_type___32); break;
        case   64: po = FNew(_pool_type___64); break;
        case  128: po = FNew(_pool_type__128); break;
        case  256: po = FNew(_pool_type__256); break;
        case  512: po = FNew(_pool_type__512); break;
        case 1024: po = FNew(_pool_type_1024); break;
        case 2048: po = FNew(_pool_type_2048); break;
        case 4096: po = FNew(_pool_type_4096); break;
        case 8192: po = FNew(_pool_type_8192); break;
        default:   po = FNew(_pool_type___64); break;
        }
        if (po)
            FStrcpyA(po->obj_name, typeid(_Ty).name());
        return push_back(id, po);
    }

    virtual pool_interface* find(FIDHASH id) = 0;
    virtual pool_interface* push_back(FIDHASH id, pool_interface* p) = 0;
    virtual void tidy() = 0;

    FLockObject cs;
};


//----------------------------------------------------------------
// 分配释放实现
//----------------------------------------------------------------
FNEW_OBJECT(0)
FNEW_OBJECT(1)
FNEW_OBJECT(2)
FNEW_OBJECT(3)
FNEW_OBJECT(4)
FNEW_OBJECT(5)
FNEW_OBJECT(6)
FNEW_OBJECT(7)
FNEW_OBJECT(8)
FNEW_OBJECT(9)
FNEW_OBJECT(10)

template < typename _Ty >
FINLINE bool FDelObject(_Ty*& p)
{
    if (!p)
        return false;
    if (!FGetObjFactory()->deallocate(p, true))
    {
        FASSERT_STR_FORCE(_T("释放一个不是由对象池创建的对象"));
        return false;
    }
    p = 0;
    return true;
}